package com.tool.cn.util;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import javax.swing.filechooser.FileSystemView;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * java 默认参数工具类
 * @author wangzh
 * @date 2018年9月21日 下午1:57:12
 */
public final class SystemUtil {
	
	private static final Logger log = LoggerFactory.getLogger(SystemUtil.class);
	
	
	/**
	 * 获取项目地址
	 */
	public static String getUrl(){
		return System.getProperty("user.dir");
	}
	
	/**
	 * 获取系统名称
	 */
	public static String getSystemName(){
		return System.getProperty("os.name");
	}
	
	/**
	 * 获取系统换行符
	 */
	public static String getNewLine(){
		return System.getProperty("line.separator");
	}
	
	/**
	 * 获取系统目录目录符号
	 */
	public static String getFileSearche(){
		return File.separator.toString();
	}
	
	/**
	 * 获取用户工作空间
	 * @return
	 */
	public static String getUserHome(){
		return System.getProperty("user.home");
	}
	
	/**
	 * 获取当前用户桌面路径
	 */
	public static String getDesktop(){
		File desktopDir = FileSystemView.getFileSystemView().getHomeDirectory();
		return desktopDir.toString();
	}
	
	/**
	 * 获取自身进程id
	 */
	public static final int getProcessID() {  
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        System.out.println(runtimeMXBean.getName());
        return Integer.valueOf(runtimeMXBean.getName().split("@")[0])  
                .intValue();  
    } 
	
	/**
	 * 程序内存使用情况
	 */
	public static final void useMemory() {
		long free = Runtime.getRuntime().freeMemory();
		long total = Runtime.getRuntime().totalMemory(); 
		StringBuffer buf = new StringBuffer();
		buf.append("[Memry: used ").append((total-free)>>20)
		.append("M free ").append(free>>20)
		.append("M total ").append(total>>20).append("M]");
		System.out.println(buf.toString());
	}
	
	/**
	 * 获取主机名
	 */
    public static String getHostName() {  
        if (System.getenv("COMPUTERNAME") != null) {    //windows
            return System.getenv("COMPUTERNAME");  
        } else if(System.getenv("HOSTNAME") !=null) {  //linux
        		return System.getenv("HOSTNAME") ;
        		
        }else {  //备用方式，速度较慢
        	try {  
                return InetAddress.getLocalHost().getHostName();  
                
            } catch (UnknownHostException e) {  
                String host = e.getMessage();
                if (host != null) {  
                    int colon = host.indexOf(':');  
                    if (colon > 0) {  
                        return host.substring(0, colon);  
                    }  
                }  
                return "UnknownHost";  
            }    
        }  
    }
    
	/**
	 * 读取tomcat配置文件，获取tomcat端口号，默认8080
	 * @return
	 */
	public static String getPort() {
		// 创建saxReader对象  
        SAXReader reader = new SAXReader();  
        // 通过read方法读取一个文件 转换成Document对象  
        Document document = null;
		try {
			document = reader.read(new File(System.getProperty("catalina.home")+File.separator+"conf"+File.separator+"server.xml"));
		} catch (DocumentException e) {
			e.printStackTrace();
		}  
        //获取根节点元素对象  
        Element node = document.getRootElement();
        
        Element server=(Element) node.elements("Service").get(0);
        
        @SuppressWarnings("unchecked")
		List<Element> result=server.elements("Connector");
        for(Element data:result) {
        	String type=data.attribute("protocol").getText();
        	if(type.contains("HTTP")||type.contains("http")) {
        		return data.attribute("port").getText();
        	}
        }
        return "8080";
	}

	private static String ipv4=null;
    /*
     * 获取本机所有网卡信息   得到所有IP信息
     * @return Inet4Address>
     */
    public static List<Inet4Address> getLocalIp4AddressFromNetworkInterface() throws SocketException {
        List<Inet4Address> addresses = new ArrayList<>(1);

        // 所有网络接口信息
        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        if (Objects.isNull(networkInterfaces)) {
            return addresses;
        }
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            //滤回环网卡、点对点网卡、非活动网卡、虚拟网卡并要求网卡名字是eth或ens开头
            if (!isValidInterface(networkInterface)) {
                continue;
            }

            // 所有网络接口的IP地址信息
            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddress = inetAddresses.nextElement();
                // 判断是否是IPv4，并且内网地址并过滤回环地址.
                if (isValidAddress(inetAddress)) {
                    addresses.add((Inet4Address) inetAddress);
                }
            }
        }
        return addresses;
    }

    /**
     * 过滤回环网卡、点对点网卡、非活动网卡、虚拟网卡并要求网卡名字是eth或ens开头
     *
     * @param ni 网卡
     * @return 如果满足要求则true，否则false
     */
    private static boolean isValidInterface(NetworkInterface ni) throws SocketException {
        return !ni.isLoopback() && !ni.isPointToPoint() && ni.isUp() && !ni.isVirtual()
                && (ni.getName().startsWith("eth") || ni.getName().startsWith("ens"));
    }

    /**
     * 判断是否是IPv4，并且内网地址并过滤回环地址.
     */
    private static boolean isValidAddress(InetAddress address) {
        return address instanceof Inet4Address && address.isSiteLocalAddress() && !address.isLoopbackAddress();
    }

    /*
     * 通过Socket 唯一确定一个IP
     * 当有多个网卡的时候，使用这种方式一般都可以得到想要的IP。甚至不要求外网地址8.8.8.8是可连通的
     * @return Inet4Address>
     */
    private static Optional<Inet4Address> getIpBySocket() throws SocketException {
        try (final DatagramSocket socket = new DatagramSocket()) {
            socket.connect(InetAddress.getByName("8.8.8.8"), 10002);
            if (socket.getLocalAddress() instanceof Inet4Address) {
                return Optional.of((Inet4Address) socket.getLocalAddress());
            }
        } catch (UnknownHostException networkInterfaces) {
            throw new RuntimeException(networkInterfaces);
        }
        return Optional.empty();
    }

    /*
     * 获取本地IPv4地址，不使用Spring boot项目
     * @return Inet4Address>
     */
    public static String getLocalIp4Address()  {
    	
    	if(ipv4==null) {
    		try {
    			final List<Inet4Address> inet4Addresses = getLocalIp4AddressFromNetworkInterface();
    			if (inet4Addresses.size() != 1) {
    			    final Optional<Inet4Address> ipBySocketOpt = getIpBySocket();
    			    if (ipBySocketOpt.isPresent()) {
    			        ipv4=ipBySocketOpt.get().getHostAddress();
    			    } else {
    			    	ipv4= inet4Addresses.isEmpty() ?null :inet4Addresses.get(0).getHostAddress();
    			    }
    			}
    			ipv4=inet4Addresses.get(0).getHostAddress();
    		} catch (Exception e) {
    			log.error("GetIpv4 Error",e);
    			ipv4=null;
    		}
    		return ipv4;
    	}else {
    		return ipv4;
    	}
    }
    
    /*
     * Spring boot获取本地IPv4地址
     * @return Inet4Address>
     */
    public static String springBootGetLocalIp4()  {
    	
    	if(ipv4==null) {
    		try {
    			ipv4=Inet4Address.getLocalHost().getHostAddress();
    		} catch (Exception e) {
    			log.error("GetIpv4 Error",e);
    		}
    		return ipv4;
    	}else {
    		return ipv4;
    	}
    }
}
